package cn.sunxyz.modules.memory;

import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * Created by yangrd on 2017/5/11.
 */
public final class DefaultNodeFactory<V> implements NodeFactory<V> {

    private Map<V, Node<V>> nodeMap = new ConcurrentHashMap<>();

    private DefaultNodeFactory() {

    }

    @Override
    public void addNode(V value) {
        nodeMap.put(value, buildNode(value));
    }

    @Override
    public void clearNode(V value) {
        if (nodeMap.containsKey(value)) {
            Node<V> node = nodeMap.get(value);
            if (null != node) {
                node.clear();
            }
            nodeMap.remove(value);
        }
    }

    @Override
    public void linkNode(V value, V... friends) {
        if (null == friends) {
            return;
        }
        Node<V> node = useNode(value);
        Collection<Node<V>> friendNodes = Arrays.asList(friends).stream().map(friend -> useNode(friend)).collect(Collectors.toList());
        node.addNodes(friendNodes);
    }


    @Override
    public Node<V> getNode(V value) {
        return nodeMap.get(value);
    }

    @Override
    public Collection<Node<V>> getNodeFriends(V value) {
        Node<V> node = getNode(value);
        if (null != node) {
            return node.getNodes();
        }
        return null;
    }

    public static <V> DefaultNodeFactory<V> getInstance() {
        return SingletonHolder.INSTANCE;
    }

    private Node<V> useNode(V value) {
        Node<V> node = Optional.ofNullable(nodeMap.get(value)).orElseGet(() -> {
            Node<V> node1 = buildNode(value);
            nodeMap.put(value, node1);
            return node1;
        });
        return node;
    }

    private Node<V> buildNode(V value) {
        return new Node<V>(value);
    }

    private static class SingletonHolder {
        private static final DefaultNodeFactory INSTANCE = new DefaultNodeFactory();
    }
}
